package cn.quan.evernote;

import java.io.IOException;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.RectF;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
/**
 * 可以auto focus的CameraView类
 * @author yunfeng.quan@gmail.com
 *
 */
final class CameraView extends SurfaceView implements SurfaceHolder.Callback {
	protected Context mContext;
	private SurfaceHolder mHolder;
	protected Camera mCamera;

	CameraView(Context context) {
		super(context);

		this.mContext = context;
		mHolder = getHolder();
		mHolder.addCallback(this);
		mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

		mLockAutoFocus = true;//缺省锁定

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		//Log.d(TAG, "-CameraPreview/surfaceCreated");
		if (mCamera == null) {
			try {
				//Log.d(TAG,"-open ");
				mCamera = Camera.open();
			} catch (RuntimeException e) {
				((Activity)mContext).finish();
				Log.e(TAG, "-camera open error:"+e.toString());
				Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_LONG).show();
			}
		}
		if(mCamera != null){
			mCamera.setPreviewCallback(new PreviewCallback() {
				@Override
				public void onPreviewFrame(byte[] data, Camera camera) {
					//Log.d(TAG, "-setPreviewCallback/onPreviewFrame");
				}
			});
			mCamera.setOneShotPreviewCallback(new PreviewCallback() {
				@Override
				public void onPreviewFrame(byte[] data, Camera camera) {
					//Log.d(TAG, "-setOneShotPreviewCallback/onPreviewFrame");
				}
			});
			mCamera.setErrorCallback(new ErrorCallback() {
				@Override
				public void onError(int error, Camera camera) {
					Log.d(TAG, "-setErrorCallback/onError"+error);
				}
			});

			try {
				//Log.d(TAG,"-setPreviewDisplay");
				mCamera.setPreviewDisplay(holder);
			} catch (IOException e) {
				Log.e(TAG, "-setPreviewDisplay error:"+e.toString());
				Log.d(TAG, "-release");
				mCamera.release();
				mCamera = null;
				((Activity)mContext).finish();
				Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_LONG).show();
			}
		}
	}
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		//Log.d(TAG, "-CameraPreview/surfaceChanged ");
		if (mCamera == null) {
			((Activity)mContext).finish();
		} else {
			//Log.d(TAG,"-stopPreview before");
			mCamera.stopPreview();
			//Log.d(TAG,"-stopPreview after");
			//camera config
			setPictureFormat(format);
			setPreviewSize(width, height);
			setPictureSize(picWidth, picHeight);//small size防止内存溢出，尽可能小照片
			//Log.d(TAG,"-startPreview before");
			mCamera.startPreview();
			//Log.d(TAG,"-startPreview after");
		}
	}
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		//Log.d(TAG, "-CameraPreview/surfaceDestroyed ");
		if (mCamera != null) {
			//Log.d(TAG,"-stopPreview");
			mCamera.stopPreview();
			mCamera.release();
			mCamera = null;
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		//Log.d(TAG, "-onTouchEvent");
        RectF shutterRect = new RectF();
        shutterRect.left = (float)(this.getWidth()*0.70);
        shutterRect.top = (float)(this.getHeight()*0.05);
        shutterRect.right = (float)(this.getWidth()*0.98);
        shutterRect.bottom = (float)(this.getHeight()*0.4);
        if(shutterRect.contains((int)event.getX(), (int)event.getY())){
        	autoFocus();
        }else{
        	notifyMessage("please touch BLUE rect.");
        }
		return true;
	}

	private IPicmoService mPicmoService;
	public void setPicmoService(IPicmoService service){
		mPicmoService = service;
	}
	private int picmoCount = 0;
	private void picmo(byte[] data){
		if(mPicmoService == null){
			Log.e(TAG,"-picmo service is null.");
			return ;
		}
		try {
			picmoCount ++;
			notifyUploadCount();
			notifyMessage("upload " + picmoCount);
			mPicmoService.picmo(data);
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	private InfoView mInfoView;
	public void setInfoView(InfoView infoView){
		mInfoView = infoView;
	}
	
	//Auto focus
	void autoFocus() {
		if(mLockAutoFocus){
			//防止重入
			return;
		}
		mLockAutoFocus = true;//Lock camera
		
		//Log.d(TAG,"-autoFocus before");
		mCamera.autoFocus(new AutoFocusCallback() {
			@Override
			public void onAutoFocus(boolean success, final Camera camera) {
				//Log.d(TAG, "-AutoFocusCallback/onAutoFocus Begin");
				ShutterCallback shutter = new ShutterCallback() {
					@Override
					public void onShutter() {
						//Log.d(TAG, "-ShutterCallback/onShutter");
					}
				};
				PictureCallback raw = new PictureCallback() {
					@Override
					public void onPictureTaken(byte[] data, Camera camera) {
						//Log.d(TAG, "-PictureCallback/raw/onPictureTaken");
					}
				};
				PictureCallback jpeg = new PictureCallback() {
					@Override
					public void onPictureTaken(byte[] data, Camera camera) {
//						Log.d(TAG, "-onPictureTaken: jpeg: data=" + data);
						//data2sd(data,"/sdcard/test.jpg");
						if(data == null){
							Log.e(TAG,"-taken data is null.");
						}
						picmo(data);
					}
				};
				//Log.d(TAG,"-takePicture before");
				camera.takePicture(shutter, raw, jpeg);
				//Log.d(TAG,"-takePicture after");
				new Thread() {
					@Override
					public void run() {
						try {
							Thread.sleep(1000);//小于1秒，容易死机. Min1秒Max3秒
						} catch (InterruptedException e) {
							Log.e(TAG, "-sleep error"+e.toString());
						}
						//Log.d(TAG,"-startPreview before");
						if(camera != null){
							camera.startPreview();
						}else{
							Log.e(TAG,"-can not start preview");
						}
						//Log.d(TAG,"-startPreview after");
						mLockAutoFocus = false;//
					}
				}.start();
				//Log.d(TAG, "-AutoFocusCallback/onAutoFocus end");
			}
		});
		//Log.d(TAG,"-autoFocus after");
	}
	//Cancel auto focus
	void cancelAutoFocus() {
		Log.d(TAG,"-cancelAutoFocus before");
		if(mCamera != null){
			mCamera.cancelAutoFocus();
		}
		Log.d(TAG,"-cancelAutoFocus after");
	}
	//

	///carema config
	protected void setPictureFormat(int format) {
		try {
			Camera.Parameters params = mCamera.getParameters();
			List<Integer> supported = params.getSupportedPictureFormats();
			if (supported != null) {
				for (int f : supported) {
					if (f == format) {
						params.setPreviewFormat(format);
						mCamera.setParameters(params);
						break;
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	protected void setPreviewSize(int width, int height) {
		Camera.Parameters params = mCamera.getParameters();
		List<Camera.Size> supported = params.getSupportedPreviewSizes();
		if (supported != null) {
			for (Camera.Size size : supported) {
				if (size.width <= width && size.height <= height) {
					params.setPreviewSize(size.width , size.height);
					mCamera.setParameters(params);
					break;
				}
			}
		}
	}
	protected void setPictureSize(int width, int height) {
		Camera.Parameters params = mCamera.getParameters();
		List<Camera.Size> supported = params.getSupportedPictureSizes();
		if (supported != null) {
			for (Camera.Size size : supported) {
				if (size.width <= width && size.height <= height) {
					params.setPictureSize(size.width, size.height);
					mCamera.setParameters(params);
					notifySize(size.width,size.height);
					break;
				}
			}
		}
	}

	protected void setAntibanding(String antibanding) {
		Camera.Parameters params = mCamera.getParameters();
		List<String> supported = params.getSupportedAntibanding();
		if (supported != null) {
			for (String ab : supported) {
				if (ab.equals(antibanding)) {
					params.setAntibanding(antibanding);
					mCamera.setParameters(params);
					break;
				}
			}
		}
	}
	protected void setColorEffect(String effect) {
		Camera.Parameters params = mCamera.getParameters();
		List<String> supported = params.getSupportedColorEffects();
		if (supported != null) {
			for (String e : supported) {
				if (e.equals(effect)) {
					params.setColorEffect(effect);
					mCamera.setParameters(params);
					break;
				}
			}
		}
	}
	protected void setFlashMode(String flash_mode) {
		Camera.Parameters params = mCamera.getParameters();
		List<String> supported = params.getSupportedFlashModes();
		if (supported != null) {
			for (String fm : supported) {
				if (fm.equals(flash_mode)) {
					params.setFlashMode(flash_mode);
					mCamera.setParameters(params);
					break;
				}
			}
		}
	}
	protected void setFocusMode(String focus_mode) {
		Camera.Parameters params = mCamera.getParameters();
		List<String> supported = params.getSupportedFocusModes();
		if (supported != null) {
			for (String fm : supported) {
				if (fm.equals(focus_mode)) {
					params.setFocusMode(focus_mode);
					mCamera.setParameters(params);
					break;
				}
			}
		}
	}
	protected void setSceneMode(String scene_mode) {
		Camera.Parameters params = mCamera.getParameters();
		List<String> supported = params.getSupportedSceneModes();
		if (supported != null) {
			for (String sm : supported) {
				if (sm.equals(scene_mode)) {
					params.setSceneMode(scene_mode);
					mCamera.setParameters(params);
					break;
				}
			}
		}
	}
	protected void setWhiteBalance(String white_balance) {
		Camera.Parameters params = mCamera.getParameters();
		List<String> supported = params.getSupportedWhiteBalance();
		if (supported != null) {
			for (String wb : supported) {
				if (wb.equals(white_balance)) {
					params.setWhiteBalance(white_balance);
					mCamera.setParameters(params);
					break;
				}
			}
		}
	}
	///lock
	public void lock(){
		if(mLockAutoFocus == false){//防止重复显示
			//TODO same message
		}
		mLockAutoFocus = true;
	}
	public void unlock(){
		if(mLockAutoFocus == true){
			//TODO same message
		}
		mLockAutoFocus = false;
	}
	///
	private Handler mHandler = new Handler();
	private void notifyMessage(String message){
		final String msg=message;
		if(mInfoView == null){
			Log.e(TAG,"-mInfoView is null");
			return;
		}
		mHandler.post(new Runnable(){
			@Override
			public void run() {
				mInfoView.notifyMessage(msg);
			}
		});
	}
	private void notifySize(int width,int height){
		final int sizeWidth = width;
		final int sizeHeight = height;
		if(mInfoView == null){
			Log.e(TAG,"-mInfoView is null");
			return;
		}
		mHandler.post(new Runnable(){
			@Override
			public void run() {
				mInfoView.notifyPicSize(sizeWidth,sizeHeight);
			}
		});
	}
	private void notifyUploadCount(){
		if(mInfoView == null){
			Log.e(TAG,"-mInfoView is null");
			return;
		}
		mHandler.post(new Runnable(){
			@Override
			public void run() {
				mInfoView.notifyInc();
			}
		});
	}

	//放在service 如果不能上传的话，就存到SD卡
	/*
	private void data2sd(byte[] data,String filename){
		Log.d(TAG, "-data2sd begin");
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(filename);
			fos.write(data);
		} catch (IOException e) {
			e.printStackTrace();
			Log.e(TAG, "-data2sd/jpeg access error:"+e.toString());
		} finally {
			if (fos != null) {
				Log.d(TAG, "-data2sd finally");
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
					Log.e(TAG, "-data2sd error:"+e.toString());
				}
			}
		}
		Log.d(TAG, "-data2sd end");
	}
	*/
	//autoFocus中锁定Camera操作
	//直到startPreview为止
	private boolean mLockAutoFocus;
	private final int picWidth = 1024;//TODO
	private final int picHeight = 768;//TODO

	private final String TAG = "**picmo**";

}
